package me.luraframework.gateway.auth.handler;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.base.Strings;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.luraframework.commons.utils.JsonUtils;
import org.springframework.data.redis.core.ReactiveRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Map;

/**
 * @ description: RedisAuthService
 * @ author: Liu Ran
 * @ data: 7/13/23 19:26
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class RedisAuthHandler implements AuthHandler {

    private static final String ONLINE_TOKEN_KEY_PREFIX_QUERY = "online-token-";

    private final ReactiveRedisTemplate<String, String> reactiveRedisTemplate;

    @Override
    public AuthType getAuthType() {
        return AuthType.REDIS;
    }

    @Override
    public String getToken(ServerWebExchange exchange) {
        String token = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        if (!Strings.isNullOrEmpty(token)) {
            return token.substring("Bearer ".length());
        }
        return token;
    }


    @Override
    public Mono<Map<String, Object>> getUserContext(ServerWebExchange exchange) {
        return reactiveRedisTemplate.opsForValue()
                                    .get(getOnlineKey(exchange))
                                    .map(str -> JsonUtils.toObj(str, new TypeReference<Map<String, Object>>() {
                                            })
                                    );
    }

    private String getOnlineKey(ServerWebExchange exchange) {
        return ONLINE_TOKEN_KEY_PREFIX_QUERY + getToken(exchange);
    }

    @Override
    public List<String> isWhitelist(ServerWebExchange exchange) {
        return null;
    }

    @Data
    public static class Config {
        private String host;
        private String password;
        private String db;
    }
}
